home *** CD-ROM | disk | FTP | other *** search
- HOW TO DO A FORBID() IN BCPL
- ============================
-
- By !LAiRFiGHT! of fLATLiNE
-
- To disable task switching on the Amiga, a normal program written in assembler
- would do something like this:
-
- move.l 4.w,a6 ;Get base of exec.library
- jsr -$84(a6) ;Call the Forbid() function
-
- However, parts of the Amiga operating system (the DOS parts) was, in the 1.x
- versions, written in a language called BCPL. Now let's take a look at how a
- Forbid() call was implemented in that language...
-
-
- ;Some other code here...
- ;...
-
- move.l #-$84,d1 ;Line 1
- moveq #$20,d0 ;Line 2
- move.l $160(a2),a4 ;Line 3
- jsr (a5) ;Line 4
-
- ;...and continue with no task switching.
-
- Explanation:
- ------------
-
- Line 1 move.l #-$84,d1
- This is an argument to the internal dos function "ExecCall".
- It is the normal function offset in exec.library (see the
- first example). The internal ExecCall function actually
- takes some more arguments. They are:
- d1 offset in exec.library
- d2 what to put in d0
- d3 what to put in d1
- d4 what to put in a0
- and the stack (the internal BCPL stack that lies in a1 and
- goes upwards) may contain values to put into a1 and a2.
- Anyway, Forbid() dosn't take any arguments so only d1 need
- to be set in this example.
-
- Line 2 moveq #$20,d0
- Wow! It uses moveq! =) Anyway, this means that the internal
- BCPL stack should be increased with $20.
-
- Line 3 move.l $160(a2),a4
- A2 always points to the internal Global Vector Table. This
- table contains addresses to the various functions to be used.
- The address to ExecCall just happens to be at $160, so fetch
- it and place it in a4...
-
- Line 4 jsr (a5)
- ...and jump to A5!?!?
-
- No it isn't a typo... it actually calls a5! This is because a5 points to the
- Function Call Routine (*sigh*), which looks like this:
-
- move.l (a7)+,a3 ;Line 1
- movem.l a1/a3-a4,-12(a1,d0.l) ;Line 2
- adda.l d0,a1 ;Line 3
- movem.l d1-d4,(a1) ;Line 4
- jmp (a4) ;Line 5
-
- Explanation:
- ------------
-
- Line 1 move.l (a7)+,a3
- Get the return address. Ofcourse, a BCPL program would NEVER
- do a normal RTS...
-
- Line 2 movem.l a1/a3-a4,-12(a1,d0.l)
- As mentioned, a1 is the internal stack pointer, and d0 was set
- to a value to increment the stack pointer with. What this line
- does, is to save the old stack pointer, and the return address
- (in a3) and the function address (in a4) just before the
- new stack, so that it can be easily (?) restored later.
-
- Line 3 adda.l d0,a1
- Increment the stack pointer.
-
- Line 4 movem.l d1-d4,(a1)
- Save the arguments to the stack. WHY???
-
- Line 5 jmp (a4)
- Phew! FINALLY call the Forbid() function. Or? Eh.. wait a
- sec... oh NO!!!? This isn't Forbid() - This is the *ExecCall*
- routine which will IN TURN call Forbid()!!!! AAARGH!
-
- Hmm.. let's take a look at the ExecCall routine then. It couldn't be THAT
- bad, could it?
-
- movem.l a0-a2/a5-a6,-(a7) ;Line 1
- move.l d1,d7 ;Line 2
- move.l d2,d0 ;Line 3
- move.l d3,d1 ;Line 4
- move.l d4,a0 ;Line 5
- move.l $14(a1),a2 ;Line 6
- move.l $10(a1),a1 ;Line 7
- move.l 4.w,a6 ;Line 8
- jsr 0(a6,d7.w) ;Line 9
- movem.l (a7)+,a0-a2/a5-a6 ;Line 10
- move.l d0,d1 ;Line 11
- jmp (a6) ;Line 12
-
-
- Explanation:
- ------------
-
- Line 1 movem.l a0-a2/a5-a6,-(a7)
- Hmm.. it uses a7 as a stack pointer?? What a funny idea!!
-
- Line 2 move.l d1,d7
- This is the offset in exec.library to which we will jsr
- later. Place it in d7.
-
- Line 3 move.l d2,d0
- BCPL arguments are always passed in d1, d2, d3 and d4, so
- take the second argument and place it in d0 (as exec (and
- other) routines often take their arguments in the low
- registers, such as d0).
-
- Line 4 move.l d3,d1
- Same thing here...
-
- Line 5 move.l d4,a0
- ...and here... Note that Forbid() doesn't require ANY
- registers to be loaded with ANYTHING...
-
- Line 6 move.l $14(a1),a2
- If it isn't enough with d1, d2, d3 and d4, let's use the
- stack instead... Offset $14 in the internal stack seems to
- contain the argument to put into a2... Note that if the
- main program in rare circumstances actually wants to SET this
- value to something, it isn't just to move it into $14(a1)...
- It has to be moved into $14(a1,d0.l), where d0 contains the
- value to add to the internal stack (as mentioned).
-
- Line 7 move.l $10(a1),a1
- Same thing here. This will also destroy a1 as a stack pointer.
- (This is why it was saved on a7... a7 isn't trashed by
- exec functions.)
-
- Line 8 move.l 4.w,a6
- Get the pointer to exec.library.
-
- Line 9 jsr 0(a6,d7.w)
- AT LAST!!!!! A call to Forbid()!!! Ta-daaa!!!!
-
- Line 10 movem.l (a7)+,a0-a2/a5-a6
- Restore what we preserved earlier...
-
- Line 11 move.l d0,d1
- Well... exec.library (along with all the other libraries I
- know of) return their result in d0. However; BCPL programs
- want their return codes in d1 (why amn't I surprised?) so let's
- just move it... (NB: Forbid() doesn't return anything
- useful...)
-
- Line 12 jmp (a6)
- Ehmm... a6??? But I though we put the return address in a3
- a while ago??? Yup, sure did. In BCPL, a6 points to the
- Return From Function Routine, which looks like this:
-
- movem.l -12(a1),a1/a3 ;Line 1
- move.l -4(a1),a4 ;Line 2
- jmp (a3) ;Line 3
-
- Explanation:
- ------------
-
- Line 1 movem.l -12(a1),a1/a3
- Get old stackpointer (before we added d0 to it) back. Also
- restore a3 (the return address).
-
- Line 2 move.l -4(a1),a4
- Get a4 from the OLD stack. A4 will now contain the value
- it had even before we changed it to contain the pointer to
- ExecCall. (It contained/contains a pointer to the section
- of code currently running...)
-
- Line 3 jmp (a3)
- ...and voilá! Return to the main program again!
-
-
- Now we just have to go through the same thing again, to do a Permit()...
-
-
-
- .-----------------------------------------------------------------------------.
- | Thanks to Maxwold for the disassembly! |
- | See you all! |
- | !LAiRFiGHT! of fLATLiNE |
- `-----------------------------------------------------------------------------'
-
- Note: They HAVE changed it in V36... =)
-